<?php


namespace app\common\command;

class ShuanQUdpService extends \think\console\Command
{
	public $server;
	public $port;
	protected function configure()
	{
		$this->setName("ShuanQUdpService")->setAliases(["栓Q验证系统UDP服务"])->addOption("notPrintMessage", null, \think\console\input\Option::VALUE_REQUIRED, "是否不打印输出信息", "false")->addOption("daemonize", null, \think\console\input\Option::VALUE_REQUIRED, "守护进程", "false")->setDescription("栓Q验证系统UDP服务");
	}
	protected function execute(\think\console\Input $input, \think\console\Output $output)
	{
		if (class_exists("swoole_server")) {
			list($ip, $port, $client) = open_swoole_client("udp", $this->port);
			$this->port = $port;
			if ($client && false) {
				if (!$input->hasOption("notPrintMessage") && $input->getOption("notPrintMessage") != "true") {
					echo "ShuanQUdpService服务已是运行状态中" . PHP_EOL;
				}
				return null;
			} else {
				$this->server = new \swoole_server($ip, $this->port, \SWOOLE_PROCESS, \SWOOLE_SOCK_UDP);
				$this->server->set(["worker_num" => 4, "daemonize" => $input->hasOption("daemonize") || $input->getOption("daemonize") == "true", "task_ipc_mode" => 3, "dispatch_mode" => 1, "log_file" => \think\facade\Env::get("root_path") . "/runtime/ShuanQUdpServiceRuntime.log"]);
				$this->server->on("packet", [$this, "onPacket"]);
				if (!$input->hasOption("notPrintMessage") && $input->getOption("notPrintMessage") != "true") {
					echo "ShuanQUdpService服务已在端口" . $port . "运行" . PHP_EOL;
				}
				$this->server->start();
			}
		} else {
			echo "未找到swoole扩展" . PHP_EOL;
		}
	}
	public function onPacket($serv, $message, $clientInfo)
	{
		file_put_contents(\think\facade\Env::get("root_path") . "runtime/ShuanQUdpService.log", json_encode(["runtime" => time(), "pid" => posix_getpid()]));
		if (!$clientInfo) {
			if ($message == "KillService") {
				echo "ShuanQTcpService服务已关闭" . PHP_EOL;
				exec("kill -9 `lsof -ti:{$this->port}`");
				unset($this->server);
			}
			return null;
		}
		echo "来自{$clientInfo["address"]}:{$clientInfo["port"]}的数据：{$message}\n";
		$StartTime = microtime(true);
		try {
			$data = json_decode($message, true);
			if (is_array($data) && isset($data["mode"])) {
				if ($data["mode"] == "client") {
					if (empty($data["api"])) {
						$this->return($serv, $clientInfo, \app\api\controller\Code::fail, "缺少api信息");
					}
					$api_info = \think\Db::name("app_api")->where("api", $data["api"])->find();
					$api_config = \think\Db::name("app_api_config")->where(["route" => $data["api"]])->find();
					if (!$api_info && !$api_config) {
						$this->return($serv, $clientInfo, \app\api\controller\Code::fail, "不存在的接口");
					} else {
						$input = $data["params"] ?? [];
						if ($api_info) {
							$app_info = \think\Db::name("app")->where("id", $input["appid"])->find();
							$api_config = \think\Db::name("app_api_config")->where(["appid" => $input["appid"]])->find();
						} else {
							$app_info = \think\Db::name("app")->where("id", $api_config["appid"])->find();
						}
						$controller_tmp = explode(".", $api_info["controller"]);
						$controller = "";
						if (is_array($controller_tmp) && count($controller_tmp) == 2) {
							$controller .= $controller_tmp[0] . "\\" . parseCamel($controller_tmp[1], true);
						} else {
							$controller .= parseCamel($controller_tmp[0], true);
						}
						$className = "\\app\\api\\controller\\" . $controller;
						$methodName = $api_info["method"];
						$class = new $className("udp", $app_info, $api_config, $api_info, $clientInfo["address"], $input, ["server" => $serv, "clientInfo" => $clientInfo]);
						$class->{$methodName}();
					}
				}
			} else {
				$this->return($serv, $clientInfo, \app\api\controller\Code::fail, "数据格式不正确");
			}
		} catch (\Exception $e) {
			echo "来自{$clientInfo["address"]}:{$clientInfo["port"]}的数据处理出现异常：{$e->getMessage()}\n";
			$ShuanQTcpServiceExceptionFilePath = \think\facade\Env::get("root_path") . "runtime/ShuanQUdpServiceException.log";
			$ShuanQTcpServiceException = "";
			if (is_file($ShuanQTcpServiceExceptionFilePath)) {
				file_get_contents($ShuanQTcpServiceExceptionFilePath);
			}
			file_put_contents($ShuanQTcpServiceExceptionFilePath, $ShuanQTcpServiceException . "\n" . "\n" . date("Y-m-d H:i:s") . "    " . $e->getMessage());
		}
		$EndTime = microtime(true);
	}
	public function return($serv, $clientInfo, $code, $message)
	{
		$serv->sendto($clientInfo["address"], $clientInfo["port"], json_encode(["code" => $code, "message" => $message], JSON_UNESCAPED_UNICODE));
	}
}